; 和 RichText 配合使用

#Include ../richText/RichText.ahk
#Include MouseEvent.ahk

Esc:: ExitApp()

g := Gui('AlwaysOnTop')
g.SetFont('s14', 'consolas')

bg := '1D2021'

g.AddText('x10 y10', 'Try click Link below')

data := [
  EndLine(),
  HK('#z'), Op('::'), Fn(' Run '), Str('"'), Link('https://www.autohotkey.com'), Str('"'), Comment('  `; Win+Z'), EndLine(),
  EndLine(),
]

; 可以更改宽，看看其他情况
rt := RichText(g, 10, 40, 100, data, { bg: bg, hardBreak: true, softBreak: true })

g.Show('h200')
g.OnEvent('Close', (*) => ExitApp())

me := MouseEvent(g.Hwnd)
links := rt._namedCtrl.Get('link')
for v in links
  RegisterLinkEvents(v, me)


HK(str) => TextData.of(str, { bg: bg, fg: 'F94834', ex: 'bold' })
Op(str) => TextData.of(str, { bg: bg, fg: '8EC07C', ex: '' })
Fn(str) => TextData.of(str, { bg: bg, fg: '8EC07C', ex: '' })
Str(str) => TextData.of(str, { bg: bg, fg: 'B5B927', ex: '' })
Link(str) => TextData(str, 'ffb700', bg, 'underline', 'link')
Comment(str) => TextData.of(str, { bg: bg, fg: '9a9a9a', ex: '' })
EndLine() => TextData.of('`n', { bg: bg, fg: 'ffffff', ex: '' })

RegisterLinkEvents(el, e) {
  static hoverC := '00bfff', pressedC := 'ff0000', defaultC := 'ffb700'
  ; 点击事件
  e.Register(MouseEvent.Events.LBUTTON_DOWN, _onClick)
  e.RegisterOnCondition(MouseEvent.Events.LBUTTON_UP, (*) => el['pressed'], _onUp)
  ; 悬浮
  e.RegisterOnCondition(MouseEvent.Events.MOUSE_MOVE, _inLinks, _onEnter, _onLeave)

  _inLinks(point, *) {  ; 当作一个整体，下面也是
    return links.findIndex(v => inEl(point, v))
  }

  _onEnter(*) {
    for v in links {
      if v['hover']
        continue
      c := el['pressed'] ? pressedC : hoverC
      v.Opt('c' c), v.Redraw(), v.hover := true
    }
  }

  _onLeave(*) {
    for v in links {
      if !v['hover']
        continue
      v.Opt('c' defaultC), v.Redraw(), v.hover := false
    }
  }

  _onClick(point, *) {
    if _inLinks(point) {
      links.foreach(v => (v.Opt('c' pressedC), v.Redraw(), v.pressed := true))
    }
  }

  _onUp(point, *) {
    if _inLinks(point) {
      _text := ''
      links.foreach(v => _text .= v.Text)
      Run(_text)
    }
    links.foreach(v => v.pressed := false)
  }
}

; ========
inBox(pos, x, y, w, h) {
  return pos.x >= x && pos.x <= x + w
    && pos.y >= y && pos.y <= y + h
}
inEl(pos, el) {
  el.GetPos(&x, &y, &w, &h)
  return inBox(pos, x, y, w, h)
}